home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Languguage OS 2
/
Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO
/
gnu
/
libg_261.zip
/
libg_261
/
libg++
/
old-stream
/
File.cc
< prev
next >
Wrap
C/C++ Source or Header
|
1992-08-12
|
11KB
|
581 lines
/*
Copyright (C) 1988 Free Software Foundation
written by Doug Lea (dl@rocky.oswego.edu)
This file is part of the GNU C++ Library. This library is free
software; you can redistribute it and/or modify it under the terms of
the GNU Library General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your
option) any later version. This library is distributed in the hope
that it will be useful, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef __GNUG__
#pragma implementation
#endif
#include <File.h>
#include <std.h>
#include <stdarg.h>
#include <values.h>
#include <sys/file.h> // needed to determine values of O_RDONLY...
#ifdef VMS
#include <errno.h> // needed to get the psect magic loaded
#define FP (*fp)
#else
#define FP fp
#endif
// error handlers
void verbose_File_error_handler(const char* msg)
{
perror(msg);
errno = 0;
}
void quiet_File_error_handler(const char*)
{
errno = 0;
}
void fatal_File_error_handler(const char* msg)
{
perror(msg);
exit(1);
}
one_arg_error_handler_t File_error_handler = verbose_File_error_handler;
one_arg_error_handler_t set_File_error_handler(one_arg_error_handler_t f)
{
one_arg_error_handler_t old = File_error_handler;
File_error_handler = f;
return old;
}
/*
Opening files.
open(filename, io_mode, access_mode) is done via system open
command since fopen doesn't handle all of the cases possible
with sys open. After a successful open, fdopen is called to
attach an _iobuf to the file descriptor.
All this requires a few decoding routines that can translate among our
enumerated types, system flags, and fopen modes.
*/
enum sys_open_cmd_io_mode // These should be correct for most systems
{
sio_read = O_RDONLY,
sio_write = O_WRONLY,
sio_readwrite = O_RDWR,
sio_append = O_APPEND
};
enum sys_open_cmd_access_mode
{
sa_create = O_CREAT,
sa_truncate = O_TRUNC,
sa_createonly = O_EXCL | O_CREAT
};
static int open_cmd_arg(io_mode i, access_mode a) // decode modes
{
int arg;
switch(i)
{
case io_readonly: arg = sio_read; break;
case io_writeonly: arg = sio_write; break;
case io_readwrite: arg = sio_readwrite; break;
case io_appendonly: arg = sio_append | sio_write; break;
case io_append: arg = sio_append | sio_readwrite; break;
default: return -1;
};
switch(a)
{
case a_createonly: return arg | sa_createonly;
case a_create: return arg | sa_create | sa_truncate;
case a_useonly: return arg;
case a_use: return arg | sa_create;
default: return -1;
}
}
static char* fopen_cmd_arg(io_mode i)
{
switch(i)
{
case io_readonly: return "r";
case io_writeonly: return "w";
case io_readwrite: return "r+";
case io_appendonly:return "a";
case io_append: return "a+";
default: return 0;
}
}
void File::initialize()
{
fp = 0; nm = 0; stat = 0; state = _bad; rw = 0;
}
// reset class vars after open
// fp->_flag inspection is isolated here
void File::reinitialize(const char* filename)
{
if (filename != 0) setname(filename);
else if (fp == stdin) setname("(stdin)");
else if (fp == stdout) setname("(stdout)");
else if (fp == stderr) setname("(stderr)");
else if (rw & 4) setname("(string)");
else setname(0);
if (fp != 0)
{
state = _good;
if (FP->_flag & (_IOREAD|_IORW))
rw |= 01;
if (FP->_flag & (_IOWRT|_IORW))
rw |= 02;
check_state();
}
else
{
set(_fail); set(_bad);
error();
}
}
File& File::open(const char* filename, io_mode m, access_mode a)
{
close();
int open_arg = open_cmd_arg(m, a);
if (open_arg != -1)
{
int fd = ::open(filename, open_arg, 0666);
if (fd >= 0)
fp = fdopen(fd, fopen_cmd_arg(m));
}
reinitialize(filename);
return *this;
}
File& File::open(const char* filename, const char* m)
{
close();
fp = fopen(filename, m);
reinitialize(filename);
return *this;
}
File& File::open(FILE* fileptr)
{
close();
fp = fileptr;
reinitialize(0);
return *this;
}
File& File::open(int filedesc, io_mode m)
{
close();
fp = fdopen(filedesc, fopen_cmd_arg(m));
reinitialize(0);
return *this;
}
File& File::close()
{
if (fp != 0)
{
#ifdef VMS
if (rw & 4) // we own the iobuf, kill it
delete(*fp); // kill the _iobuf
#endif
if (rw & 4) // we own the iobuf, kill it
delete fp;
else if (fp == stdin || fp == stdout || fp == stderr)
flush();
else
fclose(fp);
}
fp = 0;
rw = 0;
set(_bad);
return *this;
}
File& File::remove()
{
close();
return failif (nm == 0 || unlink(nm) != 0);
}
File::File()
{
initialize();
}
File::File(const char* filename, io_mode m, access_mode a)
{
initialize();
open(filename, m, a);
}
File::File(const char* filename, const char* m)
{
initialize();
open(filename, m);
}
File::File(int filedesc, io_mode m)
{
initialize();
open(filedesc, m);
}
File::File(FILE* fileptr)
{
initialize();
open(fileptr);
}
File::File(int sz, char* buf, io_mode m)
{
if (m != io_readonly && m != io_writeonly)
(*File_error_handler) ("invalid io_mode for string IO");
initialize();
rw = 4;
#ifdef VMS
_iobuf *iob;
FILE *f;
iob = new _iobuf;
f = new(FILE);
*f = iob;
fp = f;
#else
fp = new _iobuf;
#endif
#ifndef _NFILE
FP->_file = 255; // any illegal value
#else
FP->_file = _NFILE-1; // The last filedescriptor...
#ifdef BUFEND_ENTRY_TYPE
_bufendtab[FP->_file] = (BUFEND_ENTRY_TYPE)buf+sz-1;
#endif
#endif
FP->_ptr = FP->_base = buf;
#ifdef HAVE_BUFSIZ
FP->_bufsiz = sz;
#endif
if (m == io_readonly)
{
int len = 0;
while (len < sz && buf[len] != 0) ++len;
if (len == sz)
buf[sz - 1] = 0; // force null-termination!
FP->_cnt = len;
FP->_flag = _IOREAD | _IOSTRG | _IOMYBUF;
}
else
{
bzero(buf, sz); // so any result will be null-terminated
FP->_cnt = sz - 1; // leave at least one null at end
FP->_flag = _IOWRT | _IOSTRG | _IOMYBUF;
}
reinitialize(0);
}
File::~File()
{
delete(nm);
close();
}
void File::setname(const char* newname)
{
if (nm == newname) return;
if (nm != 0)
delete(nm);
if (newname != 0)
{
nm = new char[strlen(newname) + 1];
strcpy(nm, newname);
}
else
nm = 0;
}
File& File::setbuf(int buffer_kind)
{
if (!is_open())
{
set(_fail);
return *this;
}
switch(buffer_kind)
{
case _IOFBF:
#ifdef HAVE_SETVBUF
setvbuf(fp, 0, _IOFBF, 0);
#endif
break;
case _IONBF:
::setbuf(fp, 0);
break;
case _IOLBF:
#ifdef HAVE_SETLINEBUF
setlinebuf(fp);
#else
#ifdef HAVE_SETVBUF
setvbuf(fp, 0, _IOLBF, 0);
#endif
#endif
break;
default:
break;
}
return *this;
}
File& File::setbuf(int size, char* buf)
{
if (!is_open())
{
set(_fail);
return *this;
}
#ifdef HAVE_SETVBUF
setvbuf(fp, buf, _IOFBF, size);
#else
setbuffer(fp, buf, size);
#endif
return *this;
}
void File::error()
{
check_state();
set(_fail);
if (errno != 0)
{
char error_string[400];
strcpy(error_string, "\nerror in File ");
if (nm != 0)
strcat(error_string, nm);
(*File_error_handler)(error_string);
}
}
//------------------------------------------------------------------
void File::check_state() // ensure fp & state agree about eof
{
if (fp != 0)
{
if (feof(fp))
set(_eof);
else
unset(_eof);
if (ferror(fp))
set(_bad);
}
}
File& File::put(const char* s)
{
return failif(!writable() || fputs(s, fp) == EOF);
}
File& File::get(char* s, int n, char terminator)
{
if (!readable())
{
set(_fail);
return *this;
}
char ch;
stat = --n;
if (n > 0 && (get(ch)))
{
if (ch == terminator) {
unget(ch);
stat= 0; // This is not an error condition !
}
else
{
*s++ = ch; --n;
while (n > 0 && (get(ch)))
{
if (ch == terminator)
{
unget(ch);
break;
}
else
{
*s++ = ch; --n;
}
}
}
}
*s = 0;
return failif((stat != 0) && ((stat -= n) == 0));
}
File& File::getline(char* s, int n, char terminator)
{
if (!readable())
{
set(_fail);
return *this;
}
char ch;
stat = --n;
while (n > 0 && (get(ch)))
{
--n;
if ((*s++ = ch) == terminator)
break;
}
*s = 0;
return failif((stat != 0) && ((stat -= n) == 0));
}
// from Doug Schmidt
// This should probably be a page size....
#define CHUNK_SIZE 512
/* Reads an arbitrarily long input line terminated by a user-specified
TERMINATOR. Super-nifty trick using recursion avoids unnecessary calls
to NEW! */
char *File::readline (int chunk_number, char terminator)
{
char buf[CHUNK_SIZE];
register char *bufptr = buf;
register char *ptr;
char ch;
int continu;
while ((continu = !!get(ch)) && ch != terminator) /* fill the current buffer */
{
*bufptr++ = ch;
if (bufptr - buf >= CHUNK_SIZE) /* prepend remainder to ptr buffer */
{
if (ptr = readline (chunk_number + 1, terminator))
for (; bufptr != buf; *--ptr = *--bufptr);
return ptr;
}
}
if (!continu && bufptr == buf)
return NULL;
int size = (chunk_number * CHUNK_SIZE + bufptr - buf) + 1;
if (ptr = new char[stat = size])
{
for (*(ptr += (size - 1)) = '\0'; bufptr != buf; *--ptr = *--bufptr)
;
return ptr;
}
else
return NULL;
}
/* Reads an arbitrarily long input line terminated by TERMINATOR.
This routine allocates its own memory, so the user should
only supply the address of a (char *). */
File& File::gets(char **s, char terminator)
{
if (!readable())
{
set(_fail);
return *this;
}
return failif(!(*s = readline (0, terminator)));
}
#ifndef VMS
File& File::scan(const char* fmt ...)
{
if (readable())
{
va_list args;
va_start(args, fmt);
#ifndef HAVE_VSCANF
stat = _doscan(fp, fmt, args);
#else
stat = vfscanf(fp, fmt, args);
#endif
va_end(args);
failif(stat <= 0);
}
return *this;
}
#endif
File& File::form(const char* fmt ...)
{
va_list args;
va_start(args, fmt);
#ifndef HAVE_VPRINTF
stat = _doprnt(fmt, args, fp);
#ifdef HAVE_VOID_DOPRNT
stat = ferror(fp) ? -1 : 0;
#endif
#else
stat = vfprintf(fp, fmt, args);
#endif
va_end(args);
failif(stat < 0);
return *this;
}
#ifdef VMS
extern "C" {
unlink(const char *s)
{
int remove(const char *);
return remove(s);
}
}
#endif